#include "spritemanager.h"

CSpriteManager *CSpriteManager::getInstance()
{
    /**
     * @return CSpriteManager* A pointer to the single instance of this class
     */
    static CSpriteManager s_instance;
    return &s_instance;
}

CSpriteManager::~CSpriteManager()
{
    /**
     * Destructor, ensure that the memory is cleared up.
     */
    for (map<string, CSprite*>::const_iterator pSprite(m_arrSprites.begin());
         pSprite != m_arrSprites.end(); ++pSprite)
    {
        delete pSprite->second;
    }
}

CSprite* CSpriteManager::addSprite(const string &szSpriteName, 
                                   const string &szTextureName,
                                   int nWidth, int nHeight)
{
    /**
     * Adds a sprite given a texturwe name. This will check if the texture
     * exists, if not, it loads the texture.
     *
     * @param const string &szSpriteName The name of the sprite for reference
     * @param const string &szTextureName The string name reference of the 
     *  texture.
     * @return CSprite* The newly created sprite.
     */

    // Only removes if it exists
    removeSprite(szSpriteName);

    CTexture *pTexture(
        CTextureContainer::getInstance()->getTexture(szTextureName));
    if (pTexture == nullptr)
    {
        // No texture by that name, load it
        pTexture = CTextureContainer::getInstance()->addTexture(
                        szTextureName, 
                        szTextureName,
                        CDeviceManager::getInstance()->getDevice(),
                        nWidth, nHeight);
    }
    CSprite *pNewSprite(new CSprite(pTexture));
    m_arrSprites.insert(std::pair<string, CSprite*>(szSpriteName, pNewSprite));
    return pNewSprite;
}

CSprite* CSpriteManager::addSprite(const string &szSpriteName, 
                                   CTexture *pTexture)
{
    /**
     * Adds a sprite given a texture.
     *
     * @param const string &szSpriteName The name of the sprite for reference
     * @param CTexture *pTexture The texture to give to the sprite
     * @return CSprite* The newly created sprite.
     */

    // Only removes if the sprite exists already
    removeSprite(szSpriteName);

    CSprite *pNewSprite(new CSprite(pTexture));
    m_arrSprites.insert(std::pair<string, CSprite*>(szSpriteName, pNewSprite));
    return pNewSprite;
}

CSprite *CSpriteManager::getSprite(const string &szSpriteName) const
{
    /**
     * @param const string &szSpriteName The reference name of the sprite.
     * @return CSprite* A pointer to the sprite referenced by the sprite name
     */ 
    map<string, CSprite*>::const_iterator pSprite(
        m_arrSprites.find(szSpriteName));
    if (pSprite == m_arrSprites.end())
    {
        return nullptr;
    }
    return pSprite->second;
}

bool CSpriteManager::hasSprite(const string &szSpriteName) const
{
    /**
     * @return bool Whether or not the sprite exists from the given reference.
     */
    return (m_arrSprites.find(szSpriteName) != m_arrSprites.end());
}

bool CSpriteManager::removeSprite(const string &szSpriteName)
{
    /**
     * Removes a sprite from the internal container. Will only remove if exists.
     *
     * @param const string &szSpriteName The name of the sprite to remove.
     * @return bool Whether or not the sprite was successfully removed
     */ 
    map<string, CSprite*>::const_iterator pSprite(
        m_arrSprites.find(szSpriteName));
    if (pSprite != m_arrSprites.end())
    {
        delete pSprite->second;
        m_arrSprites.erase(pSprite);
        return true;
    }
    return false;
}

void CSpriteManager::render()
{
    /**
     * Loops through all of the sprites in the container and renders them in
     * turn.
     */
    for (map<string, CSprite*>::const_iterator pSprite(m_arrSprites.begin());
         pSprite != m_arrSprites.end(); ++pSprite)
    {
        pSprite->second->render();
    }
}